package com.rickpan.service;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Service;

import com.rickpan.dto.response.TeamMessageDTO;

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;
import java.util.Map;

/**
 * 消息路由策略服务
 * 负责消息路由决策、顺序保证、幂等性处理
 * 
 * @author 开发团队协调员
 * @since 2025-07-17
 */
@Service
@ConditionalOnProperty(name = "spring.rabbitmq.host", matchIfMissing = false)
public class MessageRoutingService {

    private static final Logger logger = LoggerFactory.getLogger(MessageRoutingService.class);

    @Autowired
    private TeamMessageProducer teamMessageProducer;

    // 消息序列号管理（用于顺序保证）
    private final Map<Long, AtomicLong> teamSequenceMap = new ConcurrentHashMap<>();
    
    // 消息幂等性检查（防止重复处理）
    private final Map<String, Long> messageIdempotencyMap = new ConcurrentHashMap<>();
    
    // 消息路由统计
    private final Map<String, AtomicLong> routingStatsMap = new ConcurrentHashMap<>();

    // ==================== 消息路由策略 ====================

    /**
     * 路由团队消息
     * 根据消息类型和团队配置选择最佳路由策略
     * 
     * @param message 团队消息
     * @return 路由结果
     */
    public MessageRoutingResult routeTeamMessage(TeamMessageDTO message) {
        try {
            // 1. 消息幂等性检查
            if (!checkMessageIdempotency(message)) {
                logger.warn("⚠️ 消息重复，跳过处理: teamId={}, messageId={}", 
                           message.getTeamId(), message.getId());
                return MessageRoutingResult.duplicate();
            }

            // 2. 分配消息序列号（保证顺序）
            assignMessageSequence(message);

            // 3. 选择路由策略
            RoutingStrategy strategy = selectRoutingStrategy(message);
            
            // 4. 执行路由
            boolean success = executeRouting(message, strategy);

            // 5. 更新统计信息
            updateRoutingStats(strategy.name(), success);

            logger.info("📍 消息路由完成: teamId={}, messageId={}, strategy={}, success={}",
                       message.getTeamId(), message.getId(), strategy, success);

            // 6. 根据执行结果返回相应的结果
            if (success) {
                return MessageRoutingResult.success(strategy);
            } else {
                // 路由失败，触发降级机制
                logger.warn("⚠️ 路由失败，需要降级处理: teamId={}, messageId={}, strategy={}",
                           message.getTeamId(), message.getId(), strategy);
                return MessageRoutingResult.failure(new RuntimeException("路由执行失败，需要降级"));
            }
            
        } catch (Exception e) {
            logger.error("❌ 消息路由失败: teamId={}, messageId={}", 
                        message.getTeamId(), message.getId(), e);
            return MessageRoutingResult.failure(e);
        }
    }

    /**
     * 选择路由策略
     * 
     * @param message 消息
     * @return 路由策略
     */
    private RoutingStrategy selectRoutingStrategy(TeamMessageDTO message) {
        // 阶段3：RabbitMQ基础架构已修复，现在所有消息类型都使用DIRECT_ROUTING
        // 因为我们使用的是简化的团队队列模式，不需要复杂的路由策略
        String messageType = message.getMessageType();

        logger.debug("🎯 选择路由策略: messageType={}, 使用DIRECT_ROUTING（团队队列模式）", messageType);

        // 统一使用DIRECT_ROUTING，所有消息都发送到团队队列
        return RoutingStrategy.DIRECT_ROUTING;

        /* 复杂路由策略（暂时不需要）
        switch (messageType) {
            case "text":
                return RoutingStrategy.DIRECT_ROUTING; // 文本消息使用直接路由
            case "image":
            case "file":
                return RoutingStrategy.TOPIC_ROUTING; // 文件消息使用主题路由
            case "system":
                return RoutingStrategy.FANOUT_ROUTING; // 系统消息使用广播路由
            default:
                return RoutingStrategy.DIRECT_ROUTING; // 默认使用直接路由
        }
        */
    }

    /**
     * 执行消息路由
     * 
     * @param message 消息
     * @param strategy 路由策略
     * @return 是否成功
     */
    private boolean executeRouting(TeamMessageDTO message, RoutingStrategy strategy) {
        try {
            switch (strategy) {
                case DIRECT_ROUTING:
                    teamMessageProducer.sendTeamMessage(message);
                    break;
                case TOPIC_ROUTING:
                    teamMessageProducer.sendTeamMessageWithTopicRouting(message);
                    break;
                case FANOUT_ROUTING:
                    teamMessageProducer.sendSystemBroadcast(message);
                    break;
                default:
                    teamMessageProducer.sendTeamMessage(message);
            }
            return true;
        } catch (Exception e) {
            logger.error("❌ 路由执行失败: strategy={}", strategy, e);
            return false;
        }
    }

    // ==================== 消息顺序保证 ====================

    /**
     * 为消息分配序列号
     * 确保同一团队的消息有序处理
     * 
     * @param message 消息
     */
    private void assignMessageSequence(TeamMessageDTO message) {
        Long teamId = message.getTeamId();
        AtomicLong sequence = teamSequenceMap.computeIfAbsent(teamId, k -> new AtomicLong(0));
        
        long sequenceNumber = sequence.incrementAndGet();
        
        // 将序列号存储在消息的扩展字段中（如果需要的话）
        // message.setSequenceNumber(sequenceNumber);
        
        logger.debug("🔢 消息序列号分配: teamId={}, messageId={}, sequence={}", 
                    teamId, message.getId(), sequenceNumber);
    }

    /**
     * 验证消息顺序
     * 
     * @param message 消息
     * @return 是否按顺序
     */
    public boolean validateMessageOrder(TeamMessageDTO message) {
        // 这里可以实现更复杂的顺序验证逻辑
        // 例如：检查消息的时间戳、序列号等
        return true;
    }

    // ==================== 消息幂等性处理 ====================

    /**
     * 检查消息幂等性
     * 防止重复处理同一条消息
     * 
     * @param message 消息
     * @return 是否可以处理（true=可以处理，false=重复消息）
     */
    private boolean checkMessageIdempotency(TeamMessageDTO message) {
        String idempotencyKey = generateIdempotencyKey(message);
        Long currentTime = System.currentTimeMillis();
        
        // 检查是否已处理过
        Long lastProcessTime = messageIdempotencyMap.get(idempotencyKey);
        if (lastProcessTime != null) {
            // 如果在5分钟内处理过，认为是重复消息
            if (currentTime - lastProcessTime < 300000) {
                return false;
            }
        }
        
        // 记录处理时间
        messageIdempotencyMap.put(idempotencyKey, currentTime);
        
        // 清理过期的幂等性记录（保留最近1小时的记录）
        cleanupExpiredIdempotencyRecords(currentTime);
        
        return true;
    }

    /**
     * 生成幂等性键
     * 
     * @param message 消息
     * @return 幂等性键
     */
    private String generateIdempotencyKey(TeamMessageDTO message) {
        return String.format("team_%d_msg_%d", message.getTeamId(), message.getId());
    }

    /**
     * 清理过期的幂等性记录
     * 
     * @param currentTime 当前时间
     */
    private void cleanupExpiredIdempotencyRecords(Long currentTime) {
        // 每100次检查清理一次过期记录
        if (messageIdempotencyMap.size() % 100 == 0) {
            messageIdempotencyMap.entrySet().removeIf(entry -> 
                currentTime - entry.getValue() > 3600000 // 1小时
            );
            
            if (messageIdempotencyMap.size() % 1000 == 0) {
                logger.info("🧹 清理幂等性记录: 当前记录数={}", messageIdempotencyMap.size());
            }
        }
    }

    // ==================== 路由统计 ====================

    /**
     * 更新路由统计信息
     * 
     * @param strategyName 策略名称
     * @param success 是否成功
     */
    private void updateRoutingStats(String strategyName, boolean success) {
        String key = strategyName + (success ? "_success" : "_failure");
        routingStatsMap.computeIfAbsent(key, k -> new AtomicLong(0)).incrementAndGet();
    }

    /**
     * 获取路由统计信息
     * 
     * @return 统计信息
     */
    public Map<String, Long> getRoutingStats() {
        Map<String, Long> stats = new ConcurrentHashMap<>();
        routingStatsMap.forEach((key, value) -> stats.put(key, value.get()));
        return stats;
    }

    /**
     * 重置路由统计
     */
    public void resetRoutingStats() {
        routingStatsMap.clear();
        logger.info("📊 路由统计已重置");
    }

    // ==================== 内部类和枚举 ====================

    /**
     * 路由策略枚举
     */
    public enum RoutingStrategy {
        DIRECT_ROUTING("直接路由"),
        TOPIC_ROUTING("主题路由"),
        FANOUT_ROUTING("广播路由");

        private final String description;

        RoutingStrategy(String description) {
            this.description = description;
        }

        public String getDescription() {
            return description;
        }
    }

    /**
     * 消息路由结果
     */
    public static class MessageRoutingResult {
        private final boolean success;
        private final boolean duplicate;
        private final RoutingStrategy strategy;
        private final Exception exception;

        private MessageRoutingResult(boolean success, boolean duplicate, 
                                   RoutingStrategy strategy, Exception exception) {
            this.success = success;
            this.duplicate = duplicate;
            this.strategy = strategy;
            this.exception = exception;
        }

        public static MessageRoutingResult success(RoutingStrategy strategy) {
            return new MessageRoutingResult(true, false, strategy, null);
        }

        public static MessageRoutingResult duplicate() {
            return new MessageRoutingResult(false, true, null, null);
        }

        public static MessageRoutingResult failure(Exception exception) {
            return new MessageRoutingResult(false, false, null, exception);
        }

        // Getters
        public boolean isSuccess() { return success; }
        public boolean isDuplicate() { return duplicate; }
        public RoutingStrategy getStrategy() { return strategy; }
        public Exception getException() { return exception; }
    }
}
